﻿using Inovout.Models;
using Inovout.Services;
using NHibernate.Proxy;
using System;
using System.Linq;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace Inovout.Web.Mvc
{
    public class EntityModelBinder : DefaultModelBinder
    {

        private static readonly string idKey = "Id";

        protected bool TryGetPropertyValue(ModelBindingContext bindingContext, string propertyName, out object propertyValue)
        {
            propertyValue = null;
            string fieldFullKey = CreateSubPropertyName(bindingContext.ModelName, propertyName);

            var fieldValueProviderResult = bindingContext.ValueProvider.GetValue(fieldFullKey);
            if (fieldValueProviderResult == null || string.IsNullOrEmpty(fieldValueProviderResult.AttemptedValue))
            {
                return false;
            }
            //var property = GetNHibernateProperty(bindingContext, idKey);
            DataObjectTypeDescriptor dataObjectTypeDescriptor = DataObjectTypeDescriptor.Get(bindingContext.ModelType);
            propertyValue = fieldValueProviderResult.ConvertTo(dataObjectTypeDescriptor.IdentifierProperty.MappingType);
            return true;
        }
        protected override object CreateModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext, Type modelType)
        {
            if (typeof(DataObject).IsAssignableFrom(modelType))
            {
                object idValue;
                if (TryGetPropertyValue(bindingContext, idKey, out idValue))
                {
                    IRepositoryService repositoryService = GetRepositoryService(modelType);
                    return repositoryService.FindById(idValue);
                }
            }
            if (modelType.IsInterface)
            {
                return ComponentRegistry.Resolve(modelType);
            }
            else
            {
                return base.CreateModel(controllerContext, bindingContext, modelType);
            }
        }
        protected virtual IRepositoryService GetRepositoryService(Type modelType)
        {
            Type respositoryServiceType = typeof(IRepositoryService<>);
            respositoryServiceType = respositoryServiceType.MakeGenericType(modelType);
            return ComponentRegistry.Resolve<IRepositoryService>(respositoryServiceType);
        }
        protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
        {
            if (bindingContext.Model != null && bindingContext.Model.IsProxy())
            {
                //理论上应该不会初始化。
                INHibernateProxy nhibernateProxyObject = (INHibernateProxy)bindingContext.Model;
                object idValue;
                if (TryGetPropertyValue(bindingContext, idKey, out idValue)
                    && !nhibernateProxyObject.HibernateLazyInitializer.Identifier.Equals(idValue))
                {
                    IRepositoryService repositoryService = GetRepositoryService(propertyDescriptor.PropertyType);
                    return repositoryService.FindById(idValue);
                }
            }
            else if (IsEncryptProperty(controllerContext, bindingContext))
            {
                RSACryptoServiceProvider rsa = EncryptInputExtensions.InputCertificate.PrivateKey as RSACryptoServiceProvider;
                object propertyValue = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
                var result = rsa.Decrypt(HexStringToBytes(propertyValue.ToString()), false);
                return UTF8Encoding.UTF8.GetString(result);
            }
            return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        }

        public static byte[] HexStringToBytes(string hex)
        {
            if (hex.Length == 0)
            {
                return new byte[] { 0 };
            }

            if (hex.Length % 2 == 1)
            {
                hex = "0" + hex;
            }

            byte[] result = new byte[hex.Length / 2];

            for (int i = 0; i < hex.Length / 2; i++)
            {
                result[i] = byte.Parse(hex.Substring(2 * i, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
            }

            return result;
        }

        private bool IsEncryptProperty(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext.HttpContext.Request.Form["_encrypt_property"] == null)
            {
                return false;
            }
            string[] encryptProperties = controllerContext.HttpContext.Request.Form["_encrypt_property"].Split(',');
            if (encryptProperties != null)
            {
                return encryptProperties.Contains(bindingContext.ModelName);
            }
            return false;
        }



        //    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
        //    {
        //        string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
        //        if (bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey))
        //        {
        //            ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(fullPropertyKey);
        //            TypeConverter converter = TypeDescriptor.GetConverter(propertyDescriptor.PropertyType);
        //            //值不为空！
        //            //排除Oject类型
        //            //因为Json是不能直接转换为复杂类型
        //            if (vpResult != null && !propertyDescriptor.PropertyType.Equals(typeof(object)) && !converter.CanConvertFrom(typeof(string)))
        //            {
        //                //判断是否为JSON逻辑仍不精确，最好能通过正则表达式来验证。
        //                string jsonString = (string)vpResult.AttemptedValue;
        //                jsonString = jsonString.Trim();
        //                Dictionary<string, string> jsonModelPropertyDictionary = new Dictionary<string, string>();
        //                if (jsonString.StartsWith("{") && jsonString.EndsWith("}"))
        //                {
        //                    Dictionary<string, string> jsonDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
        //                    foreach (var dicEntiry in jsonDictionary)
        //                    {
        //                        jsonModelPropertyDictionary.Add(string.Format("{0}.{1}", propertyDescriptor.Name, dicEntiry.Key), dicEntiry.Value);
        //                    }

        //                }
        //                else if (jsonString.StartsWith("[") && jsonString.EndsWith("]"))
        //                {
        //                    List<Dictionary<string, string>> jsonCollectionDictionaryList = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonString);

        //                    for (int i = 0; i < jsonCollectionDictionaryList.Count; i++)
        //                    {
        //                        string prefix = string.Format("{0}[{1}]", propertyDescriptor.Name, i.ToString());
        //                        foreach (var dicEntiry in jsonCollectionDictionaryList[i])
        //                        {
        //                            jsonModelPropertyDictionary.Add(string.Format("{0}.{1}", prefix, dicEntiry.Key), dicEntiry.Value);
        //                        }
        //                    }
        //                }
        //                if (jsonModelPropertyDictionary.Count > 1)
        //                {
        //                    bindingContext = new ModelBindingContext()
        //                    {
        //                        ModelMetadata = bindingContext.ModelMetadata
        //,
        //                        ModelState = bindingContext.ModelState,
        //                        ValueProvider = new DictionaryValueProvider<string>(jsonModelPropertyDictionary, CultureInfo.CurrentCulture)
        //                    };
        //                }
        //            }
        //            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        //        }
        //    }

    }
}

